/**
 * @file Define the ops service class
 * 
 * @author Steve Gao<gaofu@parllay.com>
 */

const path       = require('path');
const fs         = require('fs');
const os         = require('os');

const beautify = require('js-beautify').js_beautify;

const BaseService = require('./base-service').BaseService;

const {SystemServices, Configuration, EmailTemplates}   = require('../constants');

/**
 * The ops service class
 * 
 * @class OpsService
 * @extends {BaseService}
 */
class OpsService extends BaseService {

    get mailService() {
        if (!this._mailService) {
            this._mailService = this.getSystemService(SystemServices.MAIL_SERVICE);
        }

        return this._mailService;
    }

    get opsConfig() {
        if (!this._opsConfig) {
            this._opsConfig = this.getApplicationConfiguration(Configuration.OPS);
        }

        return this._opsConfig;
    }

    get appConfig() {
        if (!this._appConfig) {
            this._appConfig = this.getApplicationConfiguration(Configuration.APPLICATION);
        }

        return this._appConfig;
    }

    constructor(context) {
        super(context);
    }

    get ServerInfo() {
        var networks = os.networkInterfaces();
        var ipAdress = networks['eth0'] && networks['eth0'].length > 0 && networks['eth0'][0].address
                    || networks['eth1'] && networks['eth1'].length > 0 && networks['eth1'][0].address
                    || 'Unknown IP Address';  
        var hostname = os.hostname();

        return `${hostname}(${ipAdress}) - ${this.appConfig.env}`;
    }

    getWebRequestErrorValues(error) {
        var requestContext = error.requestContext;
        var values = {
            SERVER: this.ServerInfo,
            REQUEST_ERROR_MESSAGE: requestContext.error.message,
            REQUEST_ERROR_STACK: `<pre>${requestContext.error.stack}</pre>`,
            REQUEST_METHOD: requestContext.method,
            REQUEST_HEADERS: `<pre>${beautify(JSON.stringify(requestContext.headers))}</pre>`,
            REQUEST_URL: requestContext.url,
            REQUEST_URL_PARAMS: `<pre>${beautify(JSON.stringify(requestContext.params))}</pre>`,
            REQUEST_URL_QUERY: `<pre>${beautify(JSON.stringify(requestContext.query))}</pre>`,
            REQUEST_BODY: `<pre>${beautify(JSON.stringify(requestContext.body))}</pre>`,
            REQUEST_SESSION: `<pre>${beautify(JSON.stringify(requestContext.session))}</pre>`,
            REQUEST_START_TIME: requestContext.start_time,
            REQUEST_END_TIME: requestContext.end_time
        };
        
        return values;
    }

    /**
     * Send notification email for web request error
     * 
     * @name sendWebRequestErrorMail
     * @param {ApplicationError} error
     * 
     * @returns {void}
     * @memberOf OpsService
     */
    sendWebRequestErrorMail(error) {
        if (this.opsConfig.notification.enabled) {
            var mailOptions = {
                from: this.opsConfig.notification.from,
                to: this.opsConfig.notification.to,
                subject: this.opsConfig.notification.templates.web_request_error.subject
            };
            this.mailService.sendMailByTemplate(EmailTemplates.WEB_REQUEST_ERROR, mailOptions, this.getWebRequestErrorValues(error));
        }
    }

    getServiceErrorValues(error) {
        var requestContext = error.Context;
        var values = {
            SERVER: this.ServerInfo,
            SERVICE_ERROR_NO: error.errno || error.code,
            SERVICE_ERROR_MESSAGE: error.message,
            SERVICE_ERROR_STACK: `<pre>${error.stack}</pre>`,
            SERVICE_CONTEXT: `<pre>${beautify(JSON.stringify(error.Context))}</pre>`,
            ERROR_TYPE: error.name
        };

        return values;
    }

    /**
     * Send notification message for service error
     * 
     * @name sendServiceErrorMail
     * @param {ApplicationError} error - The appliation error
     * 
     * @returns {void}
     */
    sendServiceErrorMail(error) {
        if (this.opsConfig.notification.enabled) {
            var mailOptions = {
                from: this.opsConfig.notification.from,
                to: this.opsConfig.notification.to,
                subject: this.opsConfig.notification.templates.service_error.subject
            };
            this.mailService.sendMailByTemplate(EmailTemplates.SERVICE_ERROR, mailOptions, this.getServiceErrorValues(error));
        }
    }
}

exports.OpsService = OpsService;